package org.barad.voiceuserinterface.widgets;

import static org.barad.voiceuserinterface.VoiceInterfaceProperties.DEBUG;

import org.apache.log4j.Logger;
import org.barad.voiceuserinterface.SpeechProcessingManager;
import static org.barad.voiceuserinterface.VoiceInterfaceProperties.INTERMEDIATE_INTERACTION_PAUSE;

/**
 * This class provides multiple choice option to the user. The user
 * can choose from several predefined string values.
 * @author svetoslavganov
 *
 */
public class MultipleChoice extends Widget {
	private static final int DEFAULT_LENGTH = 10;
	private Logger log = Logger.getLogger(getClass());
	private String[] options;
	private String text;
	private boolean editable;
	private int length = DEFAULT_LENGTH;
	private boolean optionValidation = true;

	/**
	 * Interacts with the user:
	 * 	1. Announces the current value
	 *  2. Announces all the possible options
	 *  3. Stores the user's choice
	 */
	@Override
	public void interact() {
		if (isEnabled()) {
			if (DEBUG) {
				log.info("Before the interaction the value of Text " + id + " is: " + text);
			}
			outputText("Current value is");
			if (isEditable()) {
				enumerateOptions();
				inputText();
			}
			if (DEBUG) {
				log.info("After the interction the value of Text " + id + " is: " + text);
			}
		}
	}

	/**
	 * Reads text from the audio input. If the text is acceptable it
	 * is stored as current value of the widget
	 *
	 */
	public void inputText() {
		String result = SpeechProcessingManager.getInstance().listen();
		if (!isEmpty(result) && isValidOption(result)) {
			text = result;
		}
	}
	
	/**
	 * Annouces the current value of the widget and attaches an
	 * additional message as prefix if such is provided (i.e. not null 
	 * of empty string)
	 * @param additionalMessage The additional message to be added as prefix
	 */
	public void outputText(String additionalMessage) {
		String outputText = null;
		if (!isEmpty(additionalMessage)) {
			outputText = additionalMessage + " ";
		}
		if (!isEmpty(text)) {
			outputText = outputText + text;
		} 
		SpeechProcessingManager.getInstance().speak(outputText, super.wordsPerMinute);
	}
	
	/**
	 * Ennumerates all the possible options
	 */
	private void enumerateOptions() {
		SpeechProcessingManager spm = SpeechProcessingManager.getInstance();
		spm.speak("Please, provide value from the following options", wordsPerMinute);
		if (!optionsEmpty()) {
			for (int i = 0; i < options.length; i++) {
				spm.speak(options[i], wordsPerMinute);
				pause(INTERMEDIATE_INTERACTION_PAUSE);
			}
		}	
	}
	
	/**
	 * Pauses the current thread
	 * @param miliseconds The time in miliseconds
	 */
	private void pause(long miliseconds) {
		try {
			Thread.sleep(miliseconds);
		} catch (InterruptedException ie) {
			/*ignore*/
		}
	}
	
	/**
	 * Checks if a string value is in the provided 
	 * @param value
	 * @return
	 */
	private boolean isValidOption(String value) {
		for (int i = 0; i < options.length; i++) {
			if (options[i].equalsIgnoreCase(value)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Truncates a string value if is longer than the length 
	 * of the text 
	 * @param value Th value to be verified
	 * @return The value truncated to the length proprty,
	 * if needed
	 */
	private String truncate(String value) {
		if (value != null && value.length() > length) {
			return value.substring(0, length);
		}
		return value;
	}
	
	private boolean optionsEmpty() {
		return options == null || options.length == 0;
	}
	
	public boolean isEditable() {
		return editable;
	}

	public void setEditable(boolean editable) {
		this.editable = editable;
	}

	public String[] getOptions() {
		return options;
	}

	public void setOptions(String[] options) {
		if (options != null) {
			this.options = new String[options.length];
			for (int i = 0; i < options.length; i++) {
				this.options[i] = truncate(options[i]);
			}
		}
	}
	
	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}
	
	public boolean isOptionValidation() {
		return optionValidation;
	}

	public void setOptionValidation(boolean optionValidation) {
		this.optionValidation = optionValidation;
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}
}
